Add depthz_image_transport: lossless depth compression (32FC1 and 16UC1) - #238
Open
facontidavide wants to merge 2 commits into
Open
Add depthz_image_transport: lossless depth compression (32FC1 and 16UC1)#238facontidavide wants to merge 2 commits into
facontidavide wants to merge 2 commits into
Conversation
facontidavide
force-pushed
the
dpred_image_transport
branch
from
July 2, 2026 20:46
f2b9662 to
baa7870
Compare
facontidavide
marked this pull request as ready for review
July 2, 2026 21:00
|
Tick the box to add this pull request to the merge queue (same as
|
facontidavide
marked this pull request as draft
July 6, 2026 12:08
Author
|
moving back to draft. I am realizing the current depth compression based on PNG is not lossless and this creates and anfair comparison between the two. refining the work a bit |
facontidavide
force-pushed
the
dpred_image_transport
branch
from
July 6, 2026 12:51
439824b to
45d8a93
Compare
image_transport plugin for depth images, vendoring the depth codec from
facontidavide/depth_image_compression.
By default 32FC1 is quantized to a configurable uniform grid
(<base_topic>.depthz.quantization, default 0.1 mm): every decoded pixel
is within +/- half a step of the input, invalid pixels (NaN/inf/<= 0)
are preserved and decode as NaN per REP 118, and the "qpred" payload
(MED prediction on the quantization codes, zigzag + LEB128 varint
residuals, zstd) has no 16-bit level limit, so arbitrarily fine steps
and long ranges are supported. Setting quantization to 0 selects the
bit-exact lossless mode: a value dictionary + 2D prediction ("dpred")
for images with up to 65536 distinct values, and a dictionary-free
float-total-order predictor ("fpred") beyond that. 16UC1 input is
always compressed losslessly ("dpred16").
On real full-precision stereo depth the default mode compresses better
than compressedDepth (PNG) while encoding and decoding several times
faster, with a much finer, explicitly bounded quantization error.
Implementation notes:
- Blobs are fully self-describing: method, dimensions, pixel format and
quantization step are readable from the header without decompressing.
- Hot paths use runtime-dispatched AVX2 kernels next to scalar paths
that emit bit-identical blobs (and are independent of the FPU
rounding mode); decoding reconstructs along a wavefront.
- Steady-state encode/decode performs no heap allocation (thread-local
scratch, bounded-by-header zstd decompression, per-thread contexts).
- Hostile/corrupt blobs are rejected before any allocation sized from
untrusted fields; degenerate image sizes are handled; the test suite
covers round trips, error bounds, and adversarial payloads under
ASan/UBSan.
- benchmark/ contains an optional black-box perf tool (off by default,
-DDEPTHZ_BUILD_BENCHMARK=ON) that drives any image_transport plugin
end to end over frames extracted from MCAP bags.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
facontidavide
force-pushed
the
dpred_image_transport
branch
from
July 6, 2026 13:08
445c5ad to
681f651
Compare
Author
facontidavide
marked this pull request as ready for review
July 6, 2026 13:15
ahcorde
requested changes
Jul 22, 2026
ahcorde
left a comment
Contributor
There was a problem hiding this comment.
Minor comments, otherwise LGTM
| ) | ||
|
|
||
| # The vendored depth codec uses C++20 (std::countr_zero, std::endian). | ||
| target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) |
Contributor
There was a problem hiding this comment.
do you mind to use ament_cmake_ros_core to set the cpp20 version ? It should be included in this other PR for the rest of the plugins
| @@ -0,0 +1,13 @@ | |||
| <library path="depthz_image_transport"> | |||
| <class name="image_transport/depthz_pub" type="depthz_image_transport::DepthzPublisher" base_class_type="image_transport::PublisherPlugin"> | |||
Contributor
There was a problem hiding this comment.
missing
<transport_name>depthz</transport_name>
<message_type>sensor_msgs/msg/CompressedImage</message_type>
ahcorde
reviewed
Jul 22, 2026
Comment on lines
+1163
to
+1164
| parsed.header.width = get_u32(blob + pos); | ||
| parsed.header.height = get_u32(blob + pos + 4); |
Contributor
There was a problem hiding this comment.
check if the height*height doesn't overflow?
Co-authored-by: Alejandro Hernández Cordero <ahcorde@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Embracing the fact that AI is taking my (our) job, I am contributing this specialized algorithm to compress depth images.
It is approaximately 10x faster than PNG (notoriously slow) and has 30% better compression, at least on my personal dataset (that is far from being exhaustive).
I think this has a great value for the community and I hope you can give it a look 😄